/*
 *    Copyright © OpenAtom Foundation.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

package com.inspur.edp.bff.spi.assembler;

import com.inspur.edp.bff.api.exception.BffFrameworkException;
import com.inspur.edp.bff.api.manager.IFSManagerContext;
import com.inspur.edp.bff.api.manager.assembler.IExtendQueryAssembler;
import com.inspur.edp.bff.api.manager.context.QueryContext;
import com.inspur.edp.bff.spi.action.query.AbstractQueryAction;
import com.inspur.edp.bff.spi.action.query.AfterQueryAction;
import com.inspur.edp.bff.spi.action.query.BeforeQueryAction;
import com.inspur.edp.bff.spi.action.query.DefaultQueryAction;
import com.inspur.edp.bff.spi.event.query.BffQueryEventBroker;
import com.inspur.edp.cef.entity.entity.IEntityData;

import java.util.ArrayList;
import java.util.HashMap;

public abstract class AbstractExtendQueryAssembler implements IExtendQueryAssembler {

    protected abstract ArrayList<BeforeQueryAction> getBeforeQueryActions(QueryContext queryContext);

    protected abstract ArrayList<AbstractQueryAction> getQueryActions(QueryContext queryContext);

    protected abstract ArrayList<AfterQueryAction> getAfterQueryActions(QueryContext queryContext);

    public final void doBeforeQuery(IFSManagerContext context, QueryContext queryContext) {
        ArrayList<BeforeQueryAction> actions = getBeforeQueryActions(queryContext);
        if (actions == null || actions.size() < 1) {
            try {
                BffQueryEventBroker.firebeforeTotalCXQAssembler(queryContext);
                BffQueryEventBroker.fireafterTotalCXQAssembler(context, queryContext, 0);
            } catch (Exception e) {
                BffQueryEventBroker.fireQueryUnnormalStop(e);
            }
            return;
        }
        try {
            BffQueryEventBroker.firebeforeTotalCXQAssembler(queryContext);
            for (BeforeQueryAction action : actions) {
                try {
                    BffQueryEventBroker.fireBeforeCXQAssembler(action, queryContext, context);
                    action.deal(context);
                    BffQueryEventBroker.fireAfterCXQAssembler(context, queryContext);
                } catch (Exception e) {
                    BffQueryEventBroker.fireQueryUnnormalStop(e);
                    throw e;
                }

            }
            BffQueryEventBroker.fireafterTotalCXQAssembler(context, queryContext, actions.size());
        } catch (Exception e) {
            BffQueryEventBroker.fireQueryUnnormalStop(e);
            throw e;
        }

    }

    public final HashMap<String, ArrayList<IEntityData>> doQuery(IFSManagerContext context, QueryContext queryContext) {
        HashMap<String, ArrayList<IEntityData>> result = new HashMap<String, ArrayList<IEntityData>>();
        ArrayList<AbstractQueryAction> actions = getQueryActions(queryContext);
        if (actions == null || actions.size() < 1) {
            //兼容原有VO没有设置内置Query，但设置了BeforeQuery或AfterQuery
            actions = new ArrayList<AbstractQueryAction>();
            DefaultQueryAction detaultAction = new DefaultQueryAction(queryContext);
            actions.add(detaultAction);
        }
        try {
            BffQueryEventBroker.firebeforeTotalCoreQuery(queryContext);
            for (AbstractQueryAction action : actions) {
                try {
                    BffQueryEventBroker.firebeforeCoreQuery(action, queryContext, context);
                    HashMap<String, ArrayList<IEntityData>> queryData = action.deal(context);
                    mergeQueryData(result, queryData);
                    BffQueryEventBroker.fireafterCoreQuery(context, result, queryContext);
                } catch (Exception e) {
                    BffQueryEventBroker.fireQueryUnnormalStop(e);
                    throw new BffFrameworkException(e);
                }
            }
            BffQueryEventBroker.fireafterTotalCoreQuery(context, result, queryContext, actions.size());
        } catch (Exception e) {
            BffQueryEventBroker.fireQueryUnnormalStop(e);
            throw new BffFrameworkException(e);
        }
        return result;
    }

    private void mergeQueryData(HashMap<String, ArrayList<IEntityData>> result, HashMap<String, ArrayList<IEntityData>> queryData) {
        if (queryData == null || queryData.size() < 1) {
            return;
        }
        for (String node : queryData.keySet()) {
            ArrayList<IEntityData> data = queryData.get(node);
            if (result.containsKey(node)) {
                result.get(node).addAll(data);
            } else {
                result.put(node, data);
            }
        }
    }

    public final void doAfterQuery(IFSManagerContext context, QueryContext queryContext) {
        ArrayList<AfterQueryAction> actions = getAfterQueryActions(queryContext);
        if (actions == null || actions.size() < 1) {
            try {
                BffQueryEventBroker.firebeforeTotalCXHAssembler(queryContext, context);
                BffQueryEventBroker.fireafterTotalCXHAssembler(queryContext, context, 0);
            } catch (Exception e) {
                BffQueryEventBroker.fireQueryUnnormalStop(e);
            }
            return;
        }
        try {
            BffQueryEventBroker.firebeforeTotalCXHAssembler(queryContext, context);
            for (AfterQueryAction action : actions) {
                try {
                    BffQueryEventBroker.firebeforeCXHAssembler(action, queryContext, context);
                    action.deal(context);
                    BffQueryEventBroker.fireafterCXHAssembler(queryContext, context);
                } catch (Exception e) {
                    BffQueryEventBroker.fireQueryUnnormalStop(e);
                    throw new BffFrameworkException(e);
                }
            }
            BffQueryEventBroker.fireafterTotalCXHAssembler(queryContext, context, actions.size());
        } catch (Exception e) {
            BffQueryEventBroker.fireQueryUnnormalStop(e);
            throw new BffFrameworkException(e);
        }
    }

    public final ArrayList<IEntityData> cloneResultList(ArrayList<IEntityData> result) {
        ArrayList<IEntityData> newresult = new ArrayList<IEntityData>();
        for (int i = 0; i < result.size(); i++) {
            IEntityData newdata = (IEntityData) result.get(i).copy();
            newresult.add(newdata);
        }
        return newresult;
    }
}
